home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr49 / 121_01.zip / SH.C < prev    next >
Text File  |  1993-06-01  |  15KB  |  714 lines

  1. /*
  2. HEADER: CUG 121.??;
  3.  
  4.     TITLE:    sh - a 'little shell' command interpreter;
  5.     VERSION:    2.2;
  6.     DATE:    01/06/86;
  7.     DESCRIPTION: "The little shell is designed to provide a `Unix-like'
  8.         shell for CP/M, replacing the CP/M CCP as the primary user
  9.         interface.  It provides two convenient mechanisms for
  10.         chaining commands together: they may be typed on a single
  11.         line, separated by commas; or files of commands called Shell
  12.         scripts may be executed.
  13.         The CP/M operating environment does not lend itself to the
  14.         use of frequently invoked commands in the form of executable
  15.         files.  Consequently, the shell has an extensive array of
  16.         built-in commands, including: cat, ccp, cd, clr, echo, exit,
  17.         lock, logout, ls, pwd, ren, rm, sleep, unlock.
  18.         The above is accomplished at a cost:  the shell is written in
  19.         BDS C and is five times the size of the CP/M CCP; hence it
  20.         takes somewhat longer to load into memory at warm boots.
  21.         Also, since the shell clobbers the CCP, submit does not work
  22.         when the shell is invoked.";
  23.     KEYWORDS:    shell, command, interpreter;
  24.     SYSTEM:    CP/M;
  25.     FILENAME:    SH.C;
  26.     WARNINGS:    "Copyright (c) 1982 Steve Blasingame.
  27.         Requires doglob.h and fcb.h for compile.";
  28.     AUTHORS:    Steve Blasingame;
  29.     COMPILERS:    BDS-C 1.50;
  30. */
  31.  
  32. #include <bdscio.h>
  33. #include <hardware.h>
  34. #include "fcb.h"
  35. #include "doglob.h"
  36.  
  37. #define    EOT    4    /* ascii eot */
  38. #define    PROMPT    "$ "    /* prompt string */
  39. #define TABSIZE    7    /* spaces in a tab */
  40. #define    CNTLH    8    /* backspace */
  41. #define DEL    0x7f    /* ascii del */
  42. #define QUIT    0x1c    /* cntl-backslash */
  43. #define LINEKILL 24    /* cntl-x */
  44. #define    SLEEPNO    16    /* sleep constant for 4 Mz Z80a */
  45. #define COMMENT    '#'    /* comment line */
  46. #define    stdin    0    /* for console io */
  47. #define    stdout    1    /* for console io */
  48. #define    FILE    struct _buf
  49. #define SHBUF    0xf54b    /* Buffer in current bios */
  50. char    combuf[MAXLINE]; /* command line buffer */
  51. char    globs[GLOBMAX*FILENAMESIZE]; /* expansion buffer */
  52. int    argvp[20];    /* array of argument pointers */
  53. int    argcp;        /* argument count for execv */
  54. int    testmode;    /* verbose flag */
  55. int    flag;        /* for lst function */
  56.  
  57. /* Structure of Shell's Storage Area in the CBIOS */
  58. struct    exbuf    {
  59.     char    _shdsk;        /* current directory */
  60.     int    _shsav;        /* buffer save flag  */
  61.     char    _nocli;        /* no shell option */
  62.     char    _shbuf[BUFSIZ]; /* buffer */
  63. };
  64.  
  65. struct exbuf *iop;        /* pointer to bios buffer */
  66. int    parse();        /* parse command line */
  67. int    dolocal();        /* do built-in shell commands */
  68. int    lexecv();        /* local execv until C1.45a */
  69. char    *b_gets();        /* local crt driver */
  70. char    pwd();            /* return current logical disk */
  71. char    chdir();        /* select disk */
  72. int    filprt();        /* list selected file on screen */
  73. int    lst();            /* format directory listing */
  74. int    dofile();        /* process shell script */
  75. int    flock();        /* lock or unlock file */
  76. int    doshell();        /* exec the shell */
  77. int    expand();        /* expand global filenames */
  78. int    dozap();        /* interactively delete files */
  79. int    doglob();        /* parse global file expressions */
  80. int    more();            /* list multiple files on screen */
  81. int    crfil();        /* fill memory */
  82. int    strcmp();
  83.  
  84. main(argc,argv)
  85. int argc;
  86. char *argv[];
  87. {
  88. char *cp;
  89.  
  90. _allocp = 0;    /* initializer */
  91. iop = SHBUF;    /* initializer */
  92. testmode = 0;    /* initializer */
  93. iop->_nocli = 0;    /* default shell on reboot */
  94. if (argc == 2 && (strcmp(argv[1],"-T") == 0)) testmode =1;
  95. if (argc == 3 && (strcmp(argv[1],"-F") == 0)) parse(strlower(argv[2]));
  96.  
  97.  
  98.     bdos(0x0e, iop->_shdsk);    /* restore cwd */
  99.  
  100.     while (1) {
  101.         crfil(combuf,MAXLINE,0);
  102.         if (!iop->_shsav) {
  103.             puts(PROMPT);
  104.             if (!b_gets(combuf))
  105.                 break;
  106.             else {
  107.                 cp = combuf;
  108.                 if (parse(cp) == -1)
  109.                     puts("what?\n");
  110.             }
  111.         }
  112.         else {
  113.             strcpy(combuf,&iop->_shbuf);
  114.             iop->_shsav = 0;
  115.             cp = combuf;
  116.             if (parse(cp) == -1)
  117.                 puts("syntax error\n");
  118.         }
  119.     }
  120. chdir('a');            /* home directory */
  121. if (execl("a:login",0) == -1)    /* admittedly a kluge */
  122.     ;
  123. doshell();
  124. }
  125. parse(cp)
  126. char *cp;
  127. {
  128. int i;
  129. char    *pointer;
  130. i=0;
  131. argvp[i]=cp;
  132.  
  133.     if (testmode) puts(cp);
  134.     if (*cp == '\n')
  135.         return 0;
  136.     else {
  137.         while(*cp == ' ')    /* skip blanks */
  138.             cp++;
  139.         argvp[i]=cp;
  140.         while(*++cp != NULL) {
  141.             if (*cp == ' ') {
  142.                 i++;
  143.                 *cp = NULL;
  144.                 argvp[i]=cp+1;
  145.             }
  146.             else if (*cp == ';') {
  147.                 if (cp == combuf || *(cp+1) != ' ')
  148.                     return -1;
  149.                 else {
  150.                     i++;
  151.                     *cp = NULL;
  152.                     argvp[i]=NULL;
  153.                     cp += 2;
  154.                     strcpy(iop->_shbuf,cp);
  155.                     iop->_shsav = 1;
  156.                     break;
  157.                 }
  158.             }
  159.             else if (*cp == '\n') {
  160.                 i++;
  161.                 *cp = NULL;
  162.                 argvp[i]=NULL;
  163.                 break;
  164.             }
  165.         }
  166.     argcp = 0;
  167.     while(1) {
  168.         if (!argvp[argcp]) break;
  169.         argcp++;
  170.     }
  171.     if (dolocal(&argvp)) {
  172.         return 0;
  173.     }
  174.     else {
  175.         pointer = &argvp + 1;
  176.         if (lexecv(argvp[0], pointer) == -1) {
  177.             if (dofile(argcp,&argvp) == -1) {
  178.                 puts(argvp[0]);
  179.                 puts(": not found\n");
  180.             }
  181.         return 0;
  182.         }
  183.     }
  184.     }
  185. return(-1);
  186. }
  187. dolocal(ptr)
  188. char *ptr[];
  189. {
  190. int value;
  191. char *tpoint;
  192.     if (strcmp(*ptr,"clr") == 0) {
  193.         puts(CLEARS);
  194.         return 1;
  195.     }
  196.     else if (strcmp(*ptr,"ccp") == 0) {
  197.         iop->_nocli = 1;    /* set no shell mode */
  198.         bios(1,0);        /* warm boot cpm */
  199.     }
  200.     else if (strcmp(*ptr,"exit") == 0) {
  201.         iop->_shsav = 0;    /* flush shell buffer */
  202.         bios(1,0);        /* warm boot cpm */
  203.     }
  204.     else if (**ptr == COMMENT) return 1;
  205.     else if (strcmp(*ptr,"logout") == 0) {
  206.         chdir('a');    /* set default directory */
  207.         execl("a:login",0);
  208.         ;
  209.         return 1;
  210.     }
  211.     else if (strcmp(*ptr,"echo") == 0) {
  212.         ++ptr;
  213.         while (*ptr != 0) {
  214.             puts(*ptr);
  215.             putchar(' ');
  216.             ptr++;
  217.         }
  218.         putchar('\n');
  219.         return 1;
  220.     }
  221.     else if (strcmp(*ptr,"pwd") == 0) {
  222.             putchar(pwd());    /* print current disk */
  223.             puts(":\n");
  224.             return 1;
  225.     }
  226.     else if (strcmp(*ptr,"cd") == 0) {
  227.             chdir(**++ptr);    /* set default disk */
  228.         return 1;
  229.     }
  230.     else if (strcmp(*ptr,"sleep") == 0) {
  231.         value = (SLEEPNO * atoi(*++ptr));
  232.         sleep(value);
  233.         return 1;
  234.     }
  235.     else if (strcmp(*ptr,"rm") == 0) {
  236.         ++ptr;    /* remove files */
  237.         if (*ptr == 0 || **ptr == '\n' || **ptr == 0) {
  238.             puts("usage: rm [file] [file...]\n");
  239.             return 1;
  240.         }
  241.         while (*ptr != NULL && **ptr != NULL) {
  242.             expand(dozap,*ptr,0);
  243.             ptr++;
  244.         }
  245.     return 1;
  246.     }
  247.     else if (strcmp(*ptr,"lock") == 0) {
  248.         ++ptr;
  249.         if (*ptr == 0 || **ptr == '\n' || **ptr == 0) {
  250.             puts("usage: lock [file] [file...]\n");
  251.             return 1;
  252.         }
  253.         while (*ptr != NULL && **ptr != NULL) {
  254.             expand(flock,*ptr,1);
  255.             ptr++;
  256.         }
  257.     return 1;
  258.     }
  259.     else if (strcmp(*ptr,"unlock") == 0) {
  260.         ++ptr;
  261.         if (*ptr == 0 || **ptr == '\n' || **ptr == 0) {
  262.             puts("usage: unlock [file] [file...]\n");
  263.             return 1;
  264.         }
  265.         while (*ptr != NULL && **ptr != NULL) {
  266.             expand(flock,*ptr,0);
  267.             ptr++;
  268.         }
  269.     return 1;
  270.     }
  271.     else if (strcmp(*ptr,"mv") == 0) {
  272.         tpoint = *++ptr;
  273.         ++ptr;
  274.         value = *ptr;
  275.         if (tpoint == 0 || *tpoint == '\n' || **ptr == '\n' || *ptr == 0) {
  276.             puts("usage: mv [source] [dest]\n");
  277.             return 1;
  278.         }
  279.             if (index(tpoint,"*") != -1 || index(tpoint,"?") != -1) {
  280.                 puts(tpoint);
  281.                 puts(": ambiguous\n");
  282.                 return 1;
  283.             }
  284.             else if (index(value,"*") != -1 || index(value,"?") != -1) {
  285.                 puts(value);
  286.                 puts(": ambiguous\n");
  287.                 return 1;
  288.             }
  289.             else if (fstat(*ptr) == -1) {
  290.                 if ((value=fstat(tpoint)) == 1) {
  291.                     puts(tpoint);
  292.                     puts(": readonly\n");
  293.                     return 1;
  294.                 }
  295.                 else if (value == 0) {
  296.                     if (rename(tpoint,*ptr) == -1) {
  297.                         puts(*ptr);
  298.                         puts(": file not found\n");
  299.                         return 1;
  300.                     }
  301.                 }
  302.                 else if (value == -1) {
  303.                     puts(tpoint);
  304.                     puts(": file not found\n");
  305.                     return 1;
  306.                 }
  307.             }
  308.             else {
  309.                 puts(*ptr);
  310.                 puts(": file already exists\n");
  311.                 return 1;
  312.             }
  313.         return 1;
  314.     }
  315.     else if (strcmp(*ptr,"ls") == 0) {
  316.         ++ptr;
  317.         flag = 0; /* a kluge */
  318.         if (!(*ptr == 0 || **ptr == '\n' || **ptr == 0)) {
  319.             while (*ptr != NULL && **ptr != NULL) {
  320.                 expand(lst,*ptr,0);
  321.                 ptr++;
  322.             }
  323.             putchar('\n');
  324.         }
  325.         else {
  326.             expand(lst,"*.*",0);
  327.             putchar('\n');
  328.         }
  329.         return 1;
  330.     }
  331.     else if (strcmp(*ptr,"cat") == 0) {
  332.         ++ptr;
  333.         if (*ptr == 0 || **ptr == '\n' || **ptr == 0) {
  334.             puts("usage: cat [file] [file...]\n");
  335.             return 1;
  336.         }
  337.         while (*ptr != 0) {
  338.             expand(filprt,*ptr,0);
  339.             ptr++;
  340.         }
  341.         return 1;
  342.     }
  343.     else return 0;
  344. }
  345. lexecv(pgm,argv)
  346. char *pgm;
  347. char **argv;
  348. {
  349. int p[10];    /* only 10 for now */
  350. int argcp, val;
  351.     argcp=10;
  352.     val=0;
  353.  
  354.     while (*argv != NULL) {
  355.         p[11-argcp] = *argv++;
  356.         if (--argcp < 0) {
  357.             argcp = 0;
  358.             break;
  359.         }
  360.     }
  361.     p[11-argcp] = NULL;
  362.  
  363.     /* replace this grossness with something reasonable */
  364.     val=execl(pgm,p[1],p[2],p[3],p[4],p[5],p[6],p[7],p[8],p[9],p[10]);
  365.     return val;
  366. }
  367. dofile(largc,largv)
  368. int largc;
  369. char *largv[];
  370. {
  371. char local[BUFSIZ], tmpbuf[BUFSIZ], *bp, scratch[BUFSIZ];
  372. int x;
  373. FILE file;
  374. scratch[0]=0;    /* initializer */
  375.  
  376.     strcpy(local,largv[0]);
  377.     strcat(local,".sh");
  378.     if (fopen(local,file) == -1) return -1;
  379.  
  380.     while (fgets(local,file)) {
  381.         bp = local;
  382.         while (1) {
  383.             if (*bp) {
  384.                 if (*bp == '$') {
  385.                     *bp = NULL;
  386.                     strcpy(tmpbuf,local);
  387.                     if ((x=atoi(++bp)) <= largc) {
  388.                         strcat(tmpbuf,largv[x]);
  389.                     }
  390.                     else {
  391.                         puts("invalid argument\n");
  392.                         return 0;
  393.                     }
  394.                     strcat(tmpbuf,++bp);
  395.                     strcpy(local,tmpbuf);
  396.                     bp -= 2; /* klugy */
  397.                 }
  398.                 else if (*bp == '\n') {
  399.                     *bp = NULL;
  400.                 }
  401.                 bp++;
  402.             }
  403.             else break;
  404.         }
  405.         strcat(scratch,local);
  406.         strcat(scratch," ; ");
  407.         if (iop->_shsav) {
  408.             if ((strlen(iop->_shbuf)+strlen(scratch)) >= BUFSIZ) {
  409.                 puts("sh: buffer overflow\n");
  410.                 return 0;
  411.             }
  412.         }
  413.     }
  414.     if (iop->_shsav) {
  415.         strcat(scratch,iop->_shbuf);
  416.         strcpy(iop->_shbuf,scratch);
  417.     }
  418.     else {
  419.         *(scratch+strlen(scratch)-1) = NULL; /* kluge */
  420.         *(scratch+strlen(scratch)-2) = '\n'; /* more */
  421.         strcpy(iop->_shbuf,scratch);
  422.         iop->_shsav=1;
  423.     }
  424. return 0;
  425. }
  426. char *
  427. b_gets(buf)
  428. char *buf;
  429. {
  430. char c;
  431. int tab;
  432. tab = TABSIZE;
  433.  
  434.     while((c=bios(3,0)) != '\r') {
  435.         if (c == QUIT) {
  436.             puts("\nQuit\n");
  437.             bios(1,0);    /* warm boot cpm */
  438.         }
  439.         if ((c == CNTLH || c == DEL) && buf !=combuf) {
  440.             putchar(CNTLH);
  441.             putchar(' ');
  442.             putchar(CNTLH);
  443.             buf -= 2;
  444.         }
  445.         else if (c == '\t') {
  446.             putchar(' ');
  447.             while (--tab) {
  448.                 *buf = ' ';
  449.                 buf++;
  450.                 putchar(' ');
  451.             }
  452.         tab = TABSIZE;
  453.         }
  454.         else if (c == LINEKILL) {
  455.             while (1) {
  456.                 putchar(CNTLH);
  457.                 putchar(' ');
  458.                 putchar(CNTLH);
  459.                 if (buf == (combuf-1))
  460.                     break;
  461.                 else
  462.                     --buf;
  463.             }
  464.             puts(PROMPT);
  465.         }
  466.         else if (c == EOT) {
  467.             puts("logout\n");
  468.             return 0;
  469.         }
  470.         else {
  471.             *buf = c;
  472.             putchar(c);
  473.         }
  474.         if (buf != (combuf+MAXLINE))
  475.             buf++;
  476.     }
  477. putchar('\n');
  478. *buf = '\n';
  479. *++buf = '\0';
  480. return combuf;
  481. }
  482. pwd()        /* return current directory */
  483. {
  484.     return(iop->_shdsk+97);
  485. }
  486. chdir(c)    /* cp/m function 14 */
  487. char c;
  488. {
  489.     if (c < 65 || c > 122)
  490.         return 0;
  491.     c -= 97;
  492.     bdos(0x0e,c);
  493.     iop->_shdsk = c;
  494.     return c;
  495. }
  496. flock(filnam,mode) char *filnam; int mode; {
  497. fcb address;
  498. char *offset;
  499. offset = &address.f_name[8];
  500.  
  501.     setfcb(address,filnam);
  502.     if (mode == TRUE) *offset |= '\200';
  503.     else *offset &= 0x7f;
  504.     if (bdos(30,&address) == 0xff) {
  505.         puts(filnam);
  506.         puts(": not found.\n");
  507.     }
  508. return(0);
  509. }
  510. filprt(filnam)
  511. char *filnam;
  512. {
  513. FILE fbuf;
  514. char c, str[BUFSIZ];
  515. int count;
  516.  
  517.     count = 0;
  518.     if (fopen(filnam,fbuf) == -1)
  519.         return -1;
  520.     else {
  521.         puts(CLEARS);
  522.         putchar('-'); puts(filnam); puts("-\n");
  523.         for (;;) {
  524.             if (!fgets(str,fbuf)) {
  525.                 fclose(fbuf);
  526.                 fflush(fbuf);
  527.                 puts("-eof-");
  528.                 if (bios(3,0) == 'q') {
  529.                     puts("\010 \010\010 \010\010 \010\010 \010\010 \010\010 ");
  530.                     return -1;
  531.                 }
  532.                 putchar('\n');
  533.                 return 0;
  534.             }
  535.             if ((count += 1) == 22) {
  536.                 count = 0;
  537.                 puts("-more-");
  538.                 if ((c=bios(3,0)) == 'n') {
  539.                 puts("\010 \010\010 \010\010 \010\010 \010\010 \010\010 \010\010 ");
  540.                     fclose(fbuf);
  541.                     return 1;
  542.                 }
  543.                 else if (c == 'q') {
  544.                     fclose(fbuf);
  545.                     puts("\010 \010\010 \010\010 \010\010 \010\010 \010\010 \010\010 ");
  546.                     return -1;
  547.                 }
  548.                 puts(CLEARS);
  549.                 putchar('-'); puts(filnam); puts("-\n");
  550.             }
  551.             fputs(str,stdout);
  552.         }
  553.     }
  554. puts("-eof-");
  555. if (bios(3,0) == 'q') {
  556.     puts("\010 \010\010 \010\010 \010\010 \010\010 \010\010 ");
  557.     return -1;
  558. }
  559. else putchar('\n');
  560. return 0;
  561. }
  562.  
  563. lst(vector)
  564. char *vector;
  565. {
  566. int q;    /* flag must be an external */
  567.  
  568.         if (flag == 3) {
  569.             puts(vector);
  570.             putchar('\n');
  571.             flag = 0;
  572.         }
  573.         else {
  574.             puts(vector);
  575.             for (q = 0; q != (20-strlen(vector)); q++)
  576.                 putchar(' ');
  577.             flag++;
  578.         }
  579. return 0;
  580. }
  581. pickout(fcon,name) fcb *fcon; char *name; {
  582.     char i;
  583.  
  584.     if (fcon->f_entry) {
  585.         *name++ = " abcd"[fcon->f_entry & 0x7f] ;
  586.         *name++ = ':' ;
  587.     }
  588.  
  589.     for (i=0; fcon->f_name[i] != ' ' && i < 8; i++)
  590.         *name++ = tolower(fcon->f_name[i]) ;
  591.     *name++ = '.';
  592.     for (i=8; fcon->f_name[i] != ' ' && i < 11; i++)
  593.         *name++ = tolower(fcon->f_name[i]) ;
  594.     *name = 0;
  595. }
  596. remove(filnam) char *filnam; {
  597. fcb address;
  598.  
  599.     if (fstat(filnam) == 1) return 1; /* readonly file */
  600.     setfcb(address,filnam);
  601.     if (bdos(19,&address) == 0xff)    /* cpm delete call */
  602.         return -1;    /* file not found */
  603.     else return 0;
  604. }
  605. doshell()
  606. {
  607. execl("a:sh",0);
  608. }
  609. fstat(filnam) char *filnam; {
  610. char *byte, c;
  611. fcb address;
  612.  
  613.     setfcb(address,filnam);
  614.     if ((c=bdos(17,&address)) == 255)
  615.         return -1;    /* file not found */
  616.     byte =(0x80 + (c * 32) + _MBYTE); /* permission byte */
  617.  
  618.     if ((*byte & '\200') == 0) return 0; /* readwrite */
  619.     else return 1;                /* readonly */
  620. }
  621. expand(func,parm1,parm2) /* perform global file expansions */
  622. int (*func)();
  623. char *parm1;
  624. int parm2;
  625. {
  626.     int count, ret;
  627.     count = GLOBMAX;
  628.  
  629.         crfil(globs,count*FILENAMESIZE,0xff);
  630.         while (count--)
  631.             globv[count] = &globs[count*FILENAMESIZE];
  632.         globv[GLOBMAX]=0;
  633.         if ((ret = doglob(parm1)) >= 1) {
  634.             qsort(globs,ret,FILENAMESIZE,strcmp);
  635.             count = 0;
  636.             while (count < ret) {
  637.                 if ((*func)(globv[count],parm2) == -1)
  638.                     break;
  639.                 count++;
  640.             }
  641.         }
  642.         else {
  643.             puts(parm1);
  644.             puts(": no match\n");
  645.         }
  646. return 0;
  647. }
  648. dozap(file) char *file; {
  649. int ret;
  650.  
  651.     if ((ret = remove(file)) == -1) {
  652.         puts(file);
  653.         puts(": not found\n");
  654.     }
  655.     else if (ret == 1) {
  656.         puts(file);
  657.         puts(" readonly -- zap?");
  658.         if (bios(3,0) == 'y') { 
  659.             flock(file,0);
  660.             remove(file);
  661.         }
  662.         putchar('\n');
  663.     }
  664. return 0;
  665. }
  666. doglob(string) /* glob - expand filename expressions */
  667. char *string;
  668. {
  669. char f, c, buf[20];
  670. fcb address;
  671. fcb *dirbuf;
  672. int flag, q, i;
  673. flag=0;
  674. i=0;
  675.  
  676.     if (strlen(string) == 2 && *(string+1) == ':') {
  677.         setfcb(address,"????????.???");
  678.         address.f_entry = tolower(*string)-96;
  679.     }
  680.     else
  681.         setfcb(address,string);
  682.  
  683.     for (f=17; (c=bdos(f,&address)) != 255; f=18) {
  684.         dirbuf = (0x80 + (c * 32));
  685.         dirbuf->f_entry = address.f_entry; 
  686.         pickout(dirbuf, buf);
  687.             strcpy(globv[i],buf);
  688.             if (++i == GLOBMAX) break;
  689.     }
  690. globv[i] = 0;        /* null terminate vector */
  691. return i;
  692. }
  693. index(string,ch) /* return pointer to ch in string */
  694. char *string, *ch;
  695. {
  696.  
  697.     while (*string) {
  698.         if (*string==*ch)
  699.             return string;
  700.         string++;
  701.     }
  702. return -1;
  703. }
  704. crfil(address,length,byte) /* zero fill at address for length bytes */
  705. char *address, byte;
  706. unsigned length;
  707. {
  708.  
  709.     while (--length) {
  710.         *++address = byte;
  711.     }
  712. return 0;
  713. }
  714.